
import rcontrolutil
import rcontrol
import Tkinter



class RField(rcontrol.RControl):
	"""
	Properties:
	*scrollbar* - True or false. Display a vertical scrollbar. Can only be set when the control is first created, in the constructor.
	*text* - String. Current contents of the field.
	*undo* - Boolean. Enable or disable undo stack.
	
	=======
	*highlightcolor* - Color for custom hilight. 
	*bgcolor* - Background color of the field. RGB triplet, such as (255,0,0) for pure red.
	*color* - Foreground color of the field. RGB triplet.
	
	*enabled* - True or False. If False, the field is disabled, and no text can be inserted (even by code)
	*borderwidth* - An integer. Defaults to 2.
	*wrap* - Determines wrapping mode of the field. set to 'none'/False, 'char'/True, or 'word'.
	*borderstyle* - Border style. One of 'sunken','raised','groove','ridge','flat'. Default is 'sunken'.
	*font* - Set font of field. Standard tkinter font format, such as ('Times New Roman', 12, 'normal')
	*height* - Integer, where one unit is the height of a line of text. Default is 24.
	*width* - Integer, where one unit is the width of a char. Default is 80.
	"""
	
	_basecontrol = None
	_scrollbar= False
	_undo = False
	_highlightcolor = '#bbbb00'
	
	def __init__(self, strDefaultText='', scrollbar=False, parent=None, **options):
		self._scrollbar = scrollbar
		if self._scrollbar:
			import ScrolledText
			self._newWidgetManual(parent, ScrolledText.ScrolledText)
		else:
			self._newWidgetManual(parent, Tkinter.Text)
		
		if strDefaultText!='': self.text = strDefaultText
		self.set_many(**options)
	

	def get_selected_text(self):
		"""Return the text that is selected. "" (empty string) if there is no selection."""
		try:
			return self._basecontrol.get( self._basecontrol.index("sel.first"), self._basecontrol.index("sel.last"))
		except:
			return ''
			
	def get_selection(self):
		"""Return the indices of the selection. Use get_selected_text to retrieve the actual text. Position of cursor if there is no selection."""
		try:
			return self._basecontrol.index("sel.first"), self._basecontrol.index("sel.last")
		except TclError:
			try:
				return self._basecontrol.index("insert"), self._basecontrol.index("insert")
			except TclError:
				return None
				
	def deselect(self):
		"""Deselect any selection in the field."""
		self._basecontrol.tag_remove("sel","1.0",END)
	
	# Get line, or get word, 
	def highlight_clear(self):
		"""Remove highlight from text."""
		self._basecontrol.tag_remove("djhighlight","1.0",END)
	
	def highlight_line(self, nLine, bAppend=False):
		"""Highlight one line of text."""
		if not bAppend:
			self.highlight_clear()
		
		self._basecontrol.tag_add("djhighlight","%d.0"%(nLine+1), "%d.0 lineend"%(nLine+1)) #Tkinter lines start with 1
		self._basecontrol.tag_config("djhighlight",background=self._highlightcolor)
	def highlight_chars(self, c1, c2, bAppend=False):
		"""Highlight certain characters of text."""
		if not bAppend:
			self.highlight_clear()
		
		self._basecontrol.tag_add("djhighlight","1.0+%d c"%c1, "1.0+%d c"%c2)
		self._basecontrol.tag_config("djhighlight",background=self._highlightcolor)
	def set_alignment(self, line, strJustification, bAppend=True):
		"""Set alignment of certain lines of text. Justification is 'left','right','center'. line is either 'all' or a line number. Note that, currently, everything changes when you change alignment of one line."""
		justification = {'left':LEFT,'right':RIGHT,'center':CENTER}[strJustification]
		if line=='all':
			strStart, strEnd = '1.0', 'end-1c'
		else:
			nLine = int(line)
			strStart, strEnd = "%d.0"%(nLine+1), "%d.0+1c"%(nLine+1)
		if not bAppend: self._basecontrol.tag_remove("djalignment","1.0",END)
		self._basecontrol.tag_add("djalignment",strStart, strEnd)
		self._basecontrol.tag_config("djalignment",justify=justification)
	
	def insert_text(self, strText, bEnd=False):
		"""By default, inserts text into the field at the current position, replacing any current selection. If bEnd is True, appends text to the end of the field."""
		if bEnd:
			self._basecontrol.insert(END, strText)
		else:
			try: # If there is a selection, erase it
				self._basecontrol.delete( self._basecontrol.index("sel.first"), self._basecontrol.index("sel.last"))
			except TclError: # There was no text selected, so simply insert the character
				pass
			self._basecontrol.insert(INSERT, strText)
	def select_all_binding(self):
		"""Add Ctrl+A -> select all binding"""
		def sel(self):
			self.select_all()
			return 'break'
		self.bind('<Control-a>',lambda event: sel(self), '+')
		
	def select_all(self):
		"""Select all text in the field."""
		self._basecontrol.tag_add(SEL, '1.0', 'end-1c')
		self._basecontrol.mark_set(INSERT, '1.0')
		self._basecontrol.see(INSERT)
	def clear(self):
		"""Delete all text."""
		self._basecontrol.delete('1.0', END)
	
	def scrollto_start(self):
		"""Scroll to the top of field."""
		self._basecontrol.see('1.0')
	
	def scrollto_end(self):
		"""Scroll to the bottom of field."""
		self._basecontrol.see(END)
	def edit_undo(self):
		""" Undo action (if the undo property is enabled)"""
		return self._basecontrol.edit_undo()
	def edit_redo(self):
		""" Redo action (if the undo property is enabled)"""
		return self._basecontrol.edit_redo()
	
		
	def property_text_get(self):
		return self._basecontrol.get(1.0, Tkinter.END)
	def property_text_set(self, value):
		self._basecontrol.delete('1.0', Tkinter.END)
		self._basecontrol.insert(Tkinter.END, value)
		
	def property_undo_get(self):
		if value==True: 
			self._basecontrol.config(undo=True, maxundo=100)
			self._undo = True
		elif value==False:
			self._basecontrol.config(undo=False, maxundo=0)
			self._undo = False
		else: raise AttributeError, 'Must be boolean.'
	def property_undo_set(self, value):
		return self._undo			
		
	def property_highlightcolor_get(self):
		return self._basecontrol.get(1.0, Tkinter.END)
	def property_highlightcolor_set(self, value):
		self._basecontrol.delete('1.0', Tkinter.END)
		self._basecontrol.insert(Tkinter.END, value)
		
	def property_scrollbar_get(self):
		return self._scrollbar
	def property_scrollbar_set(self, value):
		raise rcontrolutil.PyRindPropertyException( 'Property can only be set when the field is first created, in the constructor.')
		
		
		
	def property_enabled_get(self):
		if self._basecontrol['state']==Tkinter.DISABLED: return False
		else: return True
	def property_enabled_set(self, value):
		if value: self._basecontrol['state'] = Tkinter.NORMAL
		else: self._basecontrol['state'] = Tkinter.DISABLED
			
		
	def property_wrap_get(self):
		d = {Tkinter.NONE:'none', Tkinter.CHAR:'char', Tkinter.WORD:'word'}
		return d[self._basecontrol['wrap']]
	def property_wrap_set(self, value):
		if value==True: self._basecontrol['wrap'] = Tkinter.CHAR
		elif value==False: self._basecontrol['wrap'] = Tkinter.NONE
		else:
			d = {'none':Tkinter.NONE, 'char':Tkinter.CHAR, 'word':Tkinter.WORD}
			self._basecontrol['wrap'] = d[value]


	_properties = { 
		
		'text': (property_text_get, property_text_set),
		'undo': (property_undo_get, property_undo_set),
		'highlightcolor': (property_highlightcolor_get, property_highlightcolor_set),
		'scrollbar': (property_scrollbar_get, property_scrollbar_set),
		
		'bgcolor': ('background',rcontrolutil.mapColor),
		'color': ('foreground',rcontrolutil.mapColor),
		'borderwidth': 'borderwidth',	
		'font': 'font',
		'width': 'width',
		'height': 'height',
		'enabled': (property_enabled_get, property_enabled_set),
		'wrap': (property_wrap_get, property_wrap_set),
		'borderstyle': ('relief',rcontrolutil.mapBorderstyle),
		
		}



